﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Hammock.Authentication.OAuth;
using Hammock;
using Payton.WP7.Common.Model;
using System.Collections.Generic;
using Payton.WP7.Common.Interface;
using Hammock.Web;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.IO.IsolatedStorage;

namespace Payton.WP7.Common
{
    public abstract class SNSServiceBase<T> where T : class
    {
        protected RestClient _client;
        protected IMappingFactory factory;

        private SNSAccount _account;
        public SNSAccount Account
        {
            get
            {
                return _account;
            }
            set
            {
                if (value != null && value != _account)
                {
                    _account = value;

                    Provider = SNSProviderManager.Current.GetProvider(Account.ServiceProvider);
                    _client = null;
                    CreateRestClient();
                    factory = MappingFactoryBase.CreateFactory(Account);
                }
            }
        }

        protected SNSProvider Provider { get; set; }

        protected virtual RestClient CreateRestClient()
        {
            //if (_client == null)
            //    _client = new RestClient
            //    {
            //        Authority = Provider.AuthSettings.CLIENT,
            //        HasElevatedPermissions = true,
            //        Credentials = CreateCredential()
            //    };
            //return _client;
            return new RestClient
            {
                Authority = Provider.AuthSettings.CLIENT,
                HasElevatedPermissions = true
            };
        }

        protected virtual Hammock.Authentication.IWebCredentials CreateCredential()
        {
            return OAuthCredentials.ForProtectedResource(
                Provider.AuthSettings.CONSUMER_KEY,
                Provider.AuthSettings.CONSUMER_KEY_SECRET,
                Account.AccessToken,
                Account.AccessTokenSecret
                );
        }

        protected virtual void PerformRequest<T1>(Action<T1, SNSResult> action, SNSRequest snsRequest) where T1 :class
        {
            RestRequest request = null;
            try
            {
                if (!TryMappingMethodString(snsRequest))
                {
                    //TO-DO
                }

                request = CreateRestRequest(snsRequest);
                // TODO Mike, add img file using request.AddFile() method

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
            }

            Helper.Log("Begin request at " + DateTime.Now.ToShortTimeString());
            Helper.Log(request.ToString());

            Execute((res) =>
            {
                try
                {
                    Helper.Log("End request at " + DateTime.Now.ToShortTimeString());
                    Helper.Log(res.Content.ToString());

                    string msg = "";
                    int isvalid = ValidateResponse(res, out msg);

                    if (isvalid == 0)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = false, Message = msg });
                        return;
                    }
                    if (isvalid == 99)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = true, Message = msg });
                        return;
                    }
                    var result = new SNSResult() { IsSuccess = true, Message = msg };
                    T1 t = MappingSingle<T1>(res.Content, result);

                    Helper.Log("End mapping at " + DateTime.Now.ToShortTimeString());
                    Helper.Log("Mapping result " + res.Content);

                    if (action != null)
                        action(t, result);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                }
            }, request);
        }


        protected virtual void PerformRequest(Action<T, SNSResult> action, SNSRequest snsRequest)
        {
            RestRequest request = null;
            try
            {
                if (!TryMappingMethodString(snsRequest))
                {
                    //TO-DO
                }

                request = CreateRestRequest(snsRequest);
                // TODO Mike, add img file using request.AddFile() method

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
            }

            Helper.Log("Begin request at " + DateTime.Now.ToShortTimeString());
            Helper.Log(request.ToString());

            Execute((res) =>
            {
                try
                {
                    Helper.Log("End request at " + DateTime.Now.ToShortTimeString());
                    Helper.Log(res.Content.ToString());

                    string msg = "";
                    int isvalid = ValidateResponse(res, out msg);

                    if (isvalid == 0)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = false, Message = msg });
                        return;
                    }
                    if (isvalid == 99)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = true, Message = msg });
                        return;
                    }
                    var result = new SNSResult() { IsSuccess = true, Message = msg };
                    T t = MappingSingle(res.Content, result);

                    Helper.Log("End mapping at " + DateTime.Now.ToShortTimeString());
                    Helper.Log("Mapping result " + res.Content);

                    if (action != null)
                        action(t, result);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                }
            }, request);
        }

        protected virtual void PerformRequest(Action<IList<T>, SNSResult> action, SNSRequest snsRequest)
        {
            RestRequest request = null;
            try
            {
                if (!TryMappingMethodString(snsRequest))
                {
                    //TO-DO
                }

                request = CreateRestRequest(snsRequest);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
            }

            Execute((res) =>
            {
                try
                {
                    Helper.Log("End request at " + DateTime.Now.ToShortTimeString());
                    Helper.Log(res.Content.ToString());

                    string msg = "";
                    int isvalid = ValidateResponse(res, out msg);

                    if (isvalid == 0)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = false, Message = msg });
                        return;
                    }
                    if (isvalid == 99)
                    {
                        if (action != null)
                            action(null, new SNSResult() { IsSuccess = true, Message = msg });
                        return;
                    }
                    var result = new SNSResult() { IsSuccess = true, Message = msg };
                    IList<T> t = null;
                    if (!string.IsNullOrEmpty(res.Content))
                        t = Mapping(res.Content, result);

                    Helper.Log("End mapping at " + DateTime.Now.ToShortTimeString());
                    //Helper.Log("Mapping result " + t.ToString());

                    if (action != null)
                        action(t, result);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                    //throw;
                }
            }, request);
        }

        protected virtual bool TryMappingMethodString(SNSRequest snsRequest)
        {
            return false;
        }

        protected virtual RestRequest CreateRestRequest(SNSRequest snsRequest)
        {
            var request = new RestRequest
            {
                Method = snsRequest.WebMethod,
                Credentials = CreateCredential()
            };

            var path = "";
            if (!string.IsNullOrEmpty(snsRequest.Method))
            {
                path += snsRequest.Method;

                if (snsRequest.Parameters.Count > 0)
                {
                    foreach (var item in snsRequest.Parameters.Where(snsRequest.Predicate))
                    {
                        if (item.Style == Model.ParameterStyle.Restful)
                        {
                            path = path.Replace(":" + item.Name, item.Value);
                        }
                        else if (item.Style == Model.ParameterStyle.Normal)
                        {
                            request.AddParameter(item.Name, item.Value);
                        }
                        else if (item.Style == Model.ParameterStyle.InHeader)
                        {
                            request.AddHeader(item.Name, item.Value);
                        }
                        else if (item.Style == ParameterStyle.Post)
                        {
                            request.AddField(item.Name, item.Value);
                        }
                        else if (item.Style == ParameterStyle.FilePath)
                        {
                            string extension = System.IO.Path.GetExtension(item.Value);
                            string filename = System.IO.Path.GetFileName(item.Value);
                            request.AddFile(item.Name, filename, item.Value, "application/octetstream");
                        }

                    }
                }

                request.Path = path.TrimEnd('&');
            }

            return request;
        }

        protected virtual Hammock.Authentication.IWebCredentials CreateCredentials(OAuthType type)
        {
            switch (type)
            {
                case OAuthType.RequestToken:
                    return OAuthCredentials.ForRequestToken(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET);
                case OAuthType.AccessToken:
                    return OAuthCredentials.ForAccessToken(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET, Account.OAuthToken, Account.OAuthTokenSecret, Account.PIN);
                case OAuthType.ProtectedResource:
                    return OAuthCredentials.ForProtectedResource(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET, Account.AccessToken, Account.AccessTokenSecret);
                case OAuthType.ClientAuthentication:
                    return OAuthCredentials.ForClientAuthentication(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET, Account.UserName, Account.Password);
            }
            return null;
        }




        protected virtual IList<T> Mapping(string res, SNSResult result)
        {
            return null;
        }

        protected virtual T MappingSingle(string res, SNSResult result)
        {
            return null;
        }

        protected virtual T MappingSingle<T>(string res, SNSResult result) where T:class
        {
            return null;
        }

        protected virtual void Execute(Action<RestResponse> action, RestRequest request)
        {
            var client = CreateRestClient();

            client.BeginRequest(request, (req, res, userstatus) =>
            {
                if (action != null)
                    action(res);
            }, null);
        }

        //return 0 means fail,1 means ok, 99 means ok but no value
        protected virtual int ValidateResponse(RestResponse o, out string msg)
        {
            if (o.Content.StartsWith("<"))
            {
                msg = o.Content;
                return 0;
            }
            msg = "";
            return 1;
        }

        protected virtual string[] GetParamtersList(SNSType type)
        {
            return new string[] { };
        }
    }
}
